package main

import (
	"errors"
	"log"
	"time"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

var (
	mgoSession *mgo.Session
)

const (
	db        = "gpssignin"
	userCol   = "users"  // phone, name, password
	signinCol = "signin" // phone, date, first, last
	gpsCol    = "gps"    // phone, time, lon, lat
)

// InitDB 初始化数据库
func InitDB() {
	var err error
	mgoSession, err = mgo.Dial("127.0.0.1:27017")
	if err != nil {
		log.Panicf("initDB() error: %v", err)
	}
	log.Printf("InitDB() success")
}

// User 用户数据
type User struct {
	Phone    string `json:"phone" bson:"phone"`
	Name     string `json:"name" bson:"name"`
	Password string `json:"password" bson:"password"`
	IsAdmin  bool   `json:"isadmin" bson:"isadmin"`
	// FirstTime time.Time `json:"-"`
	// First     string    `json:"first"`
	// LastTime  time.Time `json:"-"`
	// Last      string    `json:"last"`
	SignIn
}

// SignIn xxx
type SignIn struct {
	FirstTime time.Time `json:"-"`
	First     string    `json:"first"`
	LastTime  time.Time `json:"-"`
	Last      string    `json:"last"`
}

// 目前的所有用户数据，暂时保存在全局变量中
// var users = map[string]*User{}

// UserAlreadyExists 用户是否已经存在
func UserAlreadyExists(phone string) bool {
	// _, ok := users[phone]
	// return phone != "" && ok
	col := mgoSession.DB(db).C(userCol)
	count, _ := col.Find(bson.M{"phone": phone}).Count()
	return count > 0
}

// SaveNewUser 保存新用户
func SaveNewUser(user *User) {
	// users[user.Phone] = user
	col := mgoSession.DB(db).C(userCol)
	err := col.Insert(user)
	if err != nil {
		log.Printf("SaveNewUser error: %v", err)
	}
}

// UserLogin 用户登录。会更新打卡时间
func UserLogin(phone, password string) *User {
	user := checkUser(phone, password)
	if user == nil {
		return nil
	}

	// query signin
	now := time.Now()
	today := now.Format("2006-01-02")
	// var signIn SignIn
	col2 := mgoSession.DB(db).C(signinCol)
	err := col2.Find(bson.M{"phone": phone, "date": today}).One(&user.SignIn)
	if err != nil {
		log.Printf("siginCol.Find() error: %v", err)
	}

	user.SignIn.First = user.SignIn.FirstTime.Format("2006-01-02 15:04:05")
	user.SignIn.Last = user.SignIn.LastTime.Format("2006-01-02 15:04:05")

	// 更新first和last，并更新到db中
	if user.SignIn.FirstTime.IsZero() || user.SignIn.FirstTime.Day() < now.Day() {
		user.SignIn.FirstTime = now
		_, err = col2.Upsert(bson.M{"phone": phone, "date": today}, bson.M{"$set": bson.M{"firsttime": user.SignIn.FirstTime}})
		user.SignIn.First = now.Format("2006-01-02 15:04:05")
	}
	if user.SignIn.LastTime.IsZero() || user.SignIn.LastTime.Before(now) {
		user.SignIn.LastTime = now
		_, err = col2.Upsert(bson.M{"phone": phone, "date": today}, bson.M{"$set": bson.M{"lasttime": user.SignIn.LastTime}})
		user.SignIn.Last = now.Format("2006-01-02 15:04:05")
	}

	if err != nil {
		log.Printf("UserLogin update error: %v", err)
	}
	return user
}

func checkUser(phone, password string) *User {
	var user User
	col := mgoSession.DB(db).C(userCol)
	err := col.Find(bson.M{"phone": phone}).One(&user)
	if err != nil {
		log.Printf("UserLogin find error: %v", err)
		return nil
	}

	if user.Password != password {
		log.Printf("checkUser() error: password not match")
		return nil
	}

	return &user
}

// GPS 位置信息
type GPS struct {
	Time    time.Time `json:"-"`
	TimeStr string    `json:"time"`
	Lon     float64   `json:"lon"`
	Lat     float64   `json:"lat"`
}

// GPSSave 保存GPS
func GPSSave(phone, password string, lon, lat float64) error {
	if lon < 1 || lon > 300 || lat < 1 || lat > 300 {
		return errors.New("location invalid")
	}

	log.Printf("GPSSave()")
	user := checkUser(phone, password)
	if user == nil {
		return errors.New("checkUser error")
	}

	// timeNow := time.Now().Format("2006-01-02 15:04:05")

	col := mgoSession.DB(db).C(gpsCol)
	_, err := col.Upsert(bson.M{"phone": phone, "time": time.Now()}, bson.M{"$set": bson.M{"lon": lon, "lat": lat}})
	if err != nil {
		log.Printf("gpssave upsert error: %v", err)
		return err
	}

	return nil
}

// GPSQuery 查询GPS
func GPSQuery(phone string, start, stop time.Time) ([]*GPS, error) {
	log.Printf("GPSQuery()")
	col := mgoSession.DB(db).C(gpsCol)
	res := []*GPS{}
	err := col.Find(bson.M{"phone": phone, "time": bson.M{"$gte": start, "$lte": stop}}).All(&res)
	if err != nil {
		log.Printf("GPSQuery error: %v", err)
		return nil, err
	}

	return res, nil
}
